#include <stdlib.h>
#include <string.h>

#include <common/macro/build.h>
#include <common/macro/debug.h>
#include <common/charreader.h>

/** 
* @brief Allocate new charreader.
* 
* @return 
*/
API_LIBLOCAL charreader_t *charreader_new(void) {
	charreader_t *charreader;

	charreader = malloc(sizeof(*charreader));

	charreader->buffer = NULL;

	charreader->content = 0;
	charreader->size = 0;

	return charreader;
}

/** 
* @brief Flush data in the character reader.
* 
* @param charreader
*/
API_LIBLOCAL void charreader_flush(charreader_t *charreader) {
	assert(charreader != NULL);

	free(charreader->buffer);

	charreader->buffer = NULL;
	charreader->content = 0;
	charreader->size = 0;
}

/** 
* @brief Deallocate memory of the character reader.
* 
* @param charreader
*/
API_LIBLOCAL void charreader_destroy(charreader_t *charreader) {
	if (charreader == NULL) return;

	free(charreader->buffer);
	free(charreader);
}

/** 
* @brief Append a character at the end of the charreader.
* 
* @param charreader
* @param c
* 
* @return Zero if success, -1 if failure.
*/
API_LIBLOCAL int charreader_pushchar(charreader_t *charreader, char c) {
	assert(charreader != NULL);

	charreader->content++;
	if (charreader->size <= charreader->content) {
		charreader->size = charreader->content * 2;
		charreader->buffer = realloc(charreader->buffer, charreader->size);
	}
	charreader->buffer[charreader->content - 1] = c;

	return 0;
}

/** 
* @brief Append a string at the end of the charreader.
* 
* @param charreader
* @param s
* 
* @return Zero if success, -1 if failure.
*/
API_LIBLOCAL int charreader_pushstring(charreader_t *charreader, char *s) {
	ssize_t slen;

	assert(charreader != NULL);
	assert(s != NULL);

	slen = strlen(s);

	charreader->content += slen;
	if (charreader->size <= charreader->content) {
		charreader->size = charreader->content * 2;
		charreader->buffer = realloc(charreader->buffer, charreader->size);
	}
	memcpy(&charreader->buffer[charreader->content - slen], s, slen);

	return 0;
}

/** 
* @brief Return the size of data in the charreader.
* 
* @param charreader
* 
* @return 
*/
API_LIBLOCAL size_t charreader_getdatasize(const charreader_t *charreader) {
	assert(charreader != NULL);
	return charreader->content;
}

/** 
* @brief Return the string in the charreader buffer. It does not return
* a new copy.
* 
* @param charreader
* 
* @return 
*/
API_LIBLOCAL char *charreader_getstring(const charreader_t *charreader) {
	assert(charreader != NULL);
	return charreader->buffer;
}
